package com.eric.media.recorder;

import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import java.io.File;
import java.io.IOException;

/**
 * 声音录制工具类
 */
public class SoundRecordUtil {

	/** 用户私有录音缓存文件夹 */
	public static String PATH_USER_AUDIO = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
	/** 开始录音 */
	public static final int STATE_START_RECORD = 0;
	/** 正在录音 */
	public static final int STATE_RECORDING = 1;
	/** 结束录音 */
	public static final int STATE_STOP_RECORD = 2;
	/** 录音状态刷新时间 */
	public static final int STATE_REFRESH_TIME = 100;

	/** 振幅滤波参数 */
	private static final double EMA_FILTER = 0.6;
	/** 振幅滤波后的指数值 */
	private double mEMA = 0.0;

	/** 声音录制工具 */
	private MediaRecorder mRecorder;

	/** 开始录制时间 */
	private long startRecordTime;
	/** 结束录制时间 */
	private long stopRecordTime;
	/** 录音时长 */
	private long recordTimeLeng = 0;
	/** 录音时长 */
	private long recordTimeLength = 0;

	/** 录制的文件名 */
	private String fileName;
	/** 是否录制中 */
	private boolean isRecording = false;
	/**是否能正常录音*/
	private boolean isNormallyRecord = true;

	/** 录音监听 */
	private RecordChangeListener mChangeListener;

	private static SoundRecordUtil soundRecordUtil;

	private SoundRecordUtil() {
	}

	public synchronized static SoundRecordUtil getInstance() {
		if (soundRecordUtil == null){
			soundRecordUtil = new SoundRecordUtil();
		}
		return soundRecordUtil;
	}

	/**
	 * 设置录音文件路径
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2016/4/11,17:24
	 * <h3>UpdateTime</h3> 2016/4/11,17:24
	 * <h3>CreateAuthor</h3> luzhenbang
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 * @param pathUserAudio
	 */
	public void setPathUserAudio(String pathUserAudio){
		PATH_USER_AUDIO = pathUserAudio;
	}
	/**
	 * 开始录制
	 *
	 * @version 1.0
	 * @createTime 2014年7月4日,下午6:12:37
	 * @updateTime 2014年7月4日,下午6:12:37
	 * @createAuthor CodeApe
	 * @updateAuthor CodeApe
	 * @updateInfo (此处输入修改内容,若无修改可不写.)
	 *
	 */
	public void startRecord() {
		if (isRecording) {
			return;
		}
		startRecordTime = System.currentTimeMillis();
		stopRecordTime = -1;
		fileName = System.currentTimeMillis() + ".amr";
		File file = new File(PATH_USER_AUDIO , fileName);
//		if (!file.exists()) {
//			try {
//				file.createNewFile();
//			} catch (IOException e) {
//				e.printStackTrace();
//				return;
//			}
//		}
		mRecorder = new MediaRecorder();
		//设置音频源（使用麦克风录音）
		mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		//设置所录制的音频文件的格式 AMR用于移动设备的音频，压缩比比较大，
		// 但相对其他的压缩格式质量比较差，由于多用于人声，通话，效果还是很不错的。
		mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
		//设置所录音的编码格式
		mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
		//设置录制的音频文件的保存位置
		mRecorder.setOutputFile(file.getAbsolutePath());

		try {
			mRecorder.prepare();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			//开始录制
			mRecorder.start();
		} catch (Exception e) {
			e.printStackTrace();
			isNormallyRecord =false;
			return;
		}
		isNormallyRecord =true;
		sendMessage(handler, STATE_START_RECORD);
		isRecording = true;
	}

	/**
	 * 停止录制
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 */
	public void stopRecord() {
		if (isRecording) {
			stopRecordTime = System.currentTimeMillis();
			recordTimeLength = stopRecordTime - startRecordTime;
			if (mRecorder != null) {
				try {
					mRecorder.stop();
					mRecorder.release();
				} catch (Exception e) {
					// TODO: handle exception
				} finally {
					mRecorder = null;
					isRecording = false;
					sendMessage(handler, STATE_STOP_RECORD);
				}
			}
			mRecorder = null;
			isRecording = false;
			sendMessage(handler, STATE_STOP_RECORD);
		}
	}

	/**
	 * 获取录制文件的名称
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 * @return
	 */
	public String getRecordFileName() {
		return fileName;
	}

	/**
	 * 获取录制时长(请求成功后与刚录音时候的时差)
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 * @return
	 */
	public long getRecordTime() {
		if (System.currentTimeMillis() - startRecordTime-1000<0){
			recordTimeLeng=0;
		}else{
			recordTimeLeng = System.currentTimeMillis() - startRecordTime-1000;
		}

		return recordTimeLeng;
	}

	/**
	 * 录音是否正常（个别机型不能录音）
	 *
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 */
	public boolean getNormallyRecord(){
		return isNormallyRecord;
	}

	/**
	 * 获取录音时长
	 *
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 * @return
	 */
	public long getRecordTimeLeng() {
		return recordTimeLength;
	}

	/**
	 * 获取振幅大小
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 * @return
	 */
	public double getAmplitude() {
		if (mRecorder != null)// 2700
			return (mRecorder.getMaxAmplitude() / 3000.0);
		else
			return 0;

	}

	/**
	 * 通过滤波算法计算后的振幅平均指数
	 *
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 * @return
	 */
	public double getAmplitudeEMA() {
		double amp = getAmplitude();
		mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
		return mEMA;
	}

	/**
	 * 设置录音更改监听
	 *
	 * (此处输入方法执行任务.)
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2017/9/26,14:36
	 * <h3>UpdateTime</h3> 2017/9/26,14:36
	 * <h3>CreateAuthor</h3> Eric
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 * @param mListener
	 *            监听事件
	 */
	public void setOnRecordChangeListener(RecordChangeListener mListener) {
		this.mChangeListener = mListener;
	}

	/**
	 * 录音状态更改监听
	 */
	public interface RecordChangeListener {
		/**
		 * 录音状态更改监听
		 *
		 * @param state
		 *            当前状态
		 * @param fileName
		 *            录音文件名
		 * @param ema
		 *            录音当前振幅滤波指数
		 * @param recordLength
		 *            录音长度
		 */
		public void onChange(int state, String fileName, double ema, long recordLength);
	}

	/** 异步刷新handler对象 */
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (null == mChangeListener) {
				return;
			}
			switch (msg.what) {
			case STATE_START_RECORD://开始录制
				mChangeListener.onChange(STATE_START_RECORD, fileName, getAmplitudeEMA(), recordTimeLeng);
				handler.postDelayed(runnable, STATE_REFRESH_TIME);
				break;
			case STATE_RECORDING:
				//循环发送进度
				handler.postDelayed(runnable, STATE_REFRESH_TIME);
				break;
			case STATE_STOP_RECORD://停止录制
				mChangeListener.onChange(STATE_STOP_RECORD, fileName, getAmplitudeEMA(), recordTimeLeng);
				handler.removeCallbacks(runnable);
				break;
			}
		}

	};

	/**
	 * 异步刷新线程 （实时更新录音的进度）
	 *
	 * <h3>Version</h3> 1.0
	 * <h3>CreateTime</h3> 2016/4/21,9:26
	 * <h3>UpdateTime</h3> 2016/4/21,9:26
	 * <h3>CreateAuthor</h3> luzhenbang
	 * <h3>UpdateAuthor</h3>
	 * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
	 *
	 */
	private Runnable runnable = new Runnable() {
		@Override
		public void run() {
			mChangeListener.onChange(STATE_RECORDING, fileName, getAmplitudeEMA(), recordTimeLeng);
			handler.postDelayed(runnable, STATE_REFRESH_TIME);
		}
	};


	private void sendMessage(Handler handler, int what) {
		Message message = handler.obtainMessage();
		message.what = what;
		handler.sendMessage(message);
	}

}
